package com.xblog.chatbox.vlmp.core.dify;

import com.alibaba.fastjson2.JSONObject;
import com.xblog.chatbox.vlmp.core.VlmpAgentFeedbacks;
import com.xblog.chatbox.vlmp.core.VlmpAgentRequest;
import com.xblog.chatbox.vlmp.core.VlmpAgentResponse;
import com.xblog.chatbox.vlmp.core.dify.model.*;
import com.xiaowu.xblog.constant.MessageConstant;
import com.xiaowu.xblog.core.utils.Yao;
import okhttp3.*;
import org.apache.coyote.BadRequestException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;
import reactor.core.publisher.Flux;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Objects;
import java.util.Optional;

/**
 * @description:
 * @author: xiaowu
 * @time: 2025/8/6 22:44
 */
public class DifyAgentApi {

    private final Logger logger = LoggerFactory.getLogger(DifyAgentApi.class);

    public static Builder builder() {
        return new Builder();
    }

    private final OkHttpClient client;

    private final DifyProperties properties;

    private final DifyAgent agent;

    // 定义JSON MediaType
    private final MediaType JSON = MediaType.get("application/json; charset=utf-8");

    private DifyAgentApi(OkHttpClient client, DifyProperties properties, DifyAgent agent) {
        this.client = client;
        this.properties = properties;
        this.agent = agent;
    }

    /**
     * 流式请求
     *
     * @param request 会话请求消息
     */
    public Flux<VlmpAgentResponse> stream(VlmpAgentRequest request) {

        return Flux.create(sink -> {
            Yao.executor.execute(() -> {
                ChatCompletionRequest agentRequest = ChatCompletionRequest.builder()
                        .query(request.getText())
                        .responseMode(ChatCompletionRequest.ResponseMode.streaming)
                        .user(request.getUser())
                        .conversationId(request.getConversationId())
                        .autoGenerateName(true)
                        .build();
                if (logger.isDebugEnabled()) {
                    logger.debug(agentRequest.toString());
                }
                Request httpRequest = new Request.Builder()
                        .url(this.properties.getBaseUrl() + "/v1/chat-message")
                        .addHeader("Authorization", "Bearer" + this.agent.getAppId())
                        .addHeader("Content-Type", "application/json")
                        .post(RequestBody.create(JSONObject.toJSONString(agentRequest), JSON))
                        .build();
                //发送请求并获取响应
                try (Response httpResponse = client.newCall(httpRequest).execute()){
                    //关闭响应
                    sink.onCancel(httpResponse::close);
                    if (!httpResponse.isSuccessful()) {
                        String body= Objects.requireNonNull(httpResponse.body()).string();
                        logger.error(body);
                        sink.error(new IOException(body));
                        return;
                    }
                    ResponseBody body = httpResponse.body();
                    assert body != null;
                    try (BufferedReader reader = new BufferedReader(new InputStreamReader(body.byteStream()))){
                        String line;
                        while ((line = reader.readLine()) != null && !sink.isCancelled()) {
                           if (line.trim().isEmpty()){
                               continue;
                           }
                           if (logger.isTraceEnabled()){
                               logger.trace(line);
                           }
                           line = line.replaceFirst("data","");
                           try {
                               if (com.alibaba.fastjson.JSONObject.isValid(line)){
                                   logger.trace(line);
                                   continue;
                               }
                               //数据快
                               JSONObject chunk = JSONObject.parseObject(line, JSONObject.class);
                               String event = chunk.getString("event");
                               String conversionId = chunk.getString("conversion_Id");
                               String messageId = chunk.getString("message_id");
                               if (!StringUtils.hasText(conversionId)){
                                   sink.error(new BadRequestException(MessageConstant.CONVERSION_ERROR));
                                   break;
                               }
                               //设置会话id
                               request.setConversationId(conversionId);
                               request.setMessageId(messageId);
                               if(ChunkChatEvent.message.name().equals(event) || ChunkChatEvent.agent_message.name().equals(event)){
                                   ChunkChatMessageResponse messageResponse = chunk.toJavaObject(ChunkChatMessageResponse.class);
                                   Optional.ofNullable(messageResponse.getAnswer()).filter(answer -> !answer.isEmpty())
                                           .map(answer ->VlmpAgentResponse.text(request,answer))
                                           .ifPresent(sink::next);
                               }
                               if (ChunkChatEvent.error.name().equals(event)){
                                   logger.error("error: {}", chunk);
                                   ChunkChatErrorResponse error = chunk.toJavaObject(ChunkChatErrorResponse.class);
                                   sink.error(new RuntimeException(error.getMessage())); // JSON 解析失败等异常
                               }
                               if (ChunkChatEvent.message_end.name().equals(event)) {
                                   sink.next(VlmpAgentResponse.end(request));
                                   sink.complete(); // 结束流
                               }
                           }catch (Exception e){
                               logger.error(e.getMessage());
                               sink.error(new RuntimeException(e.getMessage()));
                           }
                        }
                    }catch (Exception e){
                        logger.error(e.getMessage());
                    }

                } catch (IOException e) {
                    throw new RuntimeException(e);
                }
            });
        });
    }

    /**
     * 非流式请求
     *
     * @param request 会话请求消息
     */
    public VlmpAgentResponse call(VlmpAgentRequest request) {
        ChatCompletionRequest agentRequest = ChatCompletionRequest.builder()
                .query(request.getText())
                .user(request.getUser())
                .conversationId(request.getConversationId())
                .autoGenerateName(true)
                .inputs(request.getMetadata())
                .responseMode(ChatCompletionRequest.ResponseMode.blocking)
                .build();

        if (logger.isDebugEnabled()) {
            logger.debug(agentRequest.toString());
        }
        Request httpRequest = new Request.Builder()
                .url(this.properties.getBaseUrl() + "/v1/chat-message")
                .addHeader("Authorization", "Bearer" + this.agent.getAppId())
                .addHeader("Content-Type", "application/json")
                .post(RequestBody.create(JSONObject.toJSONString(agentRequest), JSON))
                .build();

        // 发送请求并获取响应
        try(Response httpResponse = client.newCall(httpRequest).execute()){
            //检查相应是否成功
           if (!httpResponse.isSuccessful()) {
               String body= Objects.requireNonNull(httpResponse.body()).string();
               logger.error("Call Request Failed!: {}", body);
               throw new IOException("Unexpected");
           }
            String body = Objects.requireNonNull(httpResponse.body()).string();

            ChatCompletionResponse result = com.alibaba.fastjson.JSONObject.parseObject(body, ChatCompletionResponse.class);

            if (logger.isTraceEnabled()) {
                logger.trace("Call Request Successfully! {}", com.alibaba.fastjson.JSONObject.toJSONString(result));
            }
            //设置当前会话ID
            request.setConversationId(result.getConversationId());
            request.setMessageId(result.getMessageId());
            String answer = result.getAnswer();
            return VlmpAgentResponse.text(request, answer);
        }catch (Exception e){
            logger.error(e.getMessage());
        }
        return null;
    }

    public void delete(VlmpAgentRequest request) throws IOException{
        ChatCompletionRequest agentRequest = ChatCompletionRequest.builder()
                .user(request.getUser())
                .build();
        if (logger.isDebugEnabled()) {
            logger.debug(agentRequest.toString());
        }
        Request httpRequest = new Request.Builder()
                .url(this.properties.getBaseUrl() + "/v1/conversations")
                .addHeader("Authorization", "Bearer" + this.agent.getAppId())
                .addHeader("Content-Type", "application/json")
                .delete(RequestBody.create(JSONObject.toJSONString(agentRequest), JSON))
                .build();
        // 发送请求并获取响应
        try(Response httpResponse = client.newCall(httpRequest).execute()){
            if (!httpResponse.isSuccessful()) {
                String body= Objects.requireNonNull(httpResponse.body()).string();
                logger.error("Delete Request Failed!: {}", body);
                throw new IOException("Unexpected");
            }
            String body = Objects.requireNonNull(httpResponse.body()).string();
            logger.info("delete httpResponse: {}", body);
        }
    }

    public void rename(VlmpAgentRequest request) {
        ChatCompletionRequest agentRequest = ChatCompletionRequest.builder()
                .user(request.getUser())
                .autoGenerateName(true)
                .name(request.getConversationName())
                .build();

        if (logger.isDebugEnabled()) {
            logger.debug(com.alibaba.fastjson.JSONObject.toJSONString(agentRequest));
        }
        Request httpRequest = new Request.Builder()
                .url(this.properties.getBaseUrl() + "/v1/conversations/" + request.getConversationId() + "/name")
                .addHeader("Authorization", "Bearer " + this.agent.getAppId())
                .addHeader("Content-Type", "application/json")
                .post(RequestBody.create(com.alibaba.fastjson.JSONObject.toJSONString(agentRequest), JSON))
                .build();
        // 发送请求并获取响应
        try (Response httpResponse = client.newCall(httpRequest).execute()) {
            // 检查响应是否成功
            if (!httpResponse.isSuccessful()) {
                String body = Objects.requireNonNull(httpResponse.body()).string();
                logger.error("rename httpResponse: {}", body);
                throw new IOException("Unexpected");
            }
            String body = Objects.requireNonNull(httpResponse.body()).string();
            logger.info("rename httpResponse: {}", body);
        }catch (Exception e){
            logger.error(e.getMessage());
        }
    }

    public void feedbacks(VlmpAgentFeedbacks request) throws IOException{
        ChatFeedbackRequest feedbackRequest = ChatFeedbackRequest.builder()
                .user(request.getUser())
                .rating(request.getRating())
                .content(request.getDescription())
                .build();

        if (logger.isDebugEnabled()) {
            logger.debug(com.alibaba.fastjson.JSONObject.toJSONString(feedbackRequest));
        }
        Request httpRequest = new Request.Builder()
                .url(this.properties.getBaseUrl() + "/v1/messages/" + request.getMessageId() + "/feedbacks")
                .addHeader("Authorization", "Bearer " + this.agent.getAppId())
                .addHeader("Content-Type", "application/json")
                .post(RequestBody.create(com.alibaba.fastjson.JSONObject.toJSONString(feedbackRequest), JSON))
                .build();
        // 发送请求并获取响应
        try (Response httpResponse = client.newCall(httpRequest).execute()) {
            // 检查响应是否成功
            if (!httpResponse.isSuccessful()) {
                String body = Objects.requireNonNull(httpResponse.body()).string();
                logger.error("feedbacks response: {}", body);
                throw new IOException("Unexpected :" + httpResponse);
            }
            String body = Objects.requireNonNull(httpResponse.body()).string();
            logger.info("feedbacks response: {}", body);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static class Builder {

        public Builder() {
        }


        private OkHttpClient client;

        private DifyProperties properties;

        private DifyAgent agent;

        public Builder client(OkHttpClient client) {
            this.client = client;
            return this;
        }

        public Builder properties(DifyProperties properties) {
            this.properties = properties;
            return this;
        }

        public Builder agent(DifyAgent agent) {
            this.agent = agent;
            return this;
        }


        public DifyAgentApi build() {
            return new DifyAgentApi(this.client, this.properties, agent);
        }

    }

}
